<!DOCTYPE html>
<html>

<head>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <meta charset="utf-8">
    <title>d3 force</title>
    <style>
        .link {
            fill: none;
            stroke: #666;
            stroke-width: 1.8px;
        }

        /*#licensing {
	  fill: green;
	}

	.link.licensing {
	  stroke: green;
	}*/

        .link.Dot {
            stroke-dasharray: 0, 3 3;
        }

        circle {
            fill: #ccc;
            stroke: #333;
            stroke-width: 1.5px;
        }

        text {
            font: 14px sans-serif;
            pointer-events: none;
            /*text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;*/
        }

        /*circle .resolved {fill:red;}*/
        #graphs {
            width: 100%;
        }
    </style>
</head>

<body>
    <div id="graphs"></div>
</body>
<script>
    (function (window) {

        var data = {
            "nodes": [{
                    "name": "周氏2",
                    "color": "#8E8E8E",
                    "id": 0,
                    "module_id": "1663",
                    "size": 1
                },
                {
                    "name": "周氏4",
                    "color": "#EA0000",
                    "id": 1,
                    "module_id": "1667",
                    "size": 1
                },
                {
                    "name": "周氏",
                    "color": "#FF359A",
                    "id": 2,
                    "module_id": "2518",
                    "size": 4
                },
                {
                    "name": "周氏3",
                    "color": "#FF00FF",
                    "id": 3,
                    "module_id": "2504",
                    "size": 2
                }
            ],
            "links": [{
                    "source": 0,
                    "target": 1,
                    "value": "Line",
                    "cause_module_id": "1663",
                    "result_module_id": "1667",
                    "length": 1
                },
                {
                    "source": 2,
                    "target": 1,
                    "value": "Line",
                    "cause_module_id": "2518",
                    "result_module_id": "1667",
                    "length": 1
                },
                {
                    "source": 2,
                    "target": 0,
                    "value": "Line",
                    "cause_module_id": "2518",
                    "result_module_id": "1663",
                    "length": 1
                },
                {
                    "source": 1,
                    "target": 2,
                    "value": "Line",
                    "cause_module_id": "1667",
                    "result_module_id": "2518",
                    "length": 1
                },
                {
                    "source": 0,
                    "target": 2,
                    "value": "Line",
                    "cause_module_id": "1663",
                    "result_module_id": "2518",
                    "length": 1
                },
                {
                    "source": 3,
                    "target": 2,
                    "value": "Line",
                    "cause_module_id": "2504",
                    "result_module_id": "2518",
                    "length": 1
                }
            ]
        };

        function renderGraphs() {
            var margin = {
                    top: 50,
                    right: 8,
                    bottom: 50,
                    left: 8
                },
                width = 900,
                height = 900;


            $("#graphs").empty();
            // color 区别颜色 value区别是虚线，还是实线
            var graph = data,
                len = graph.nodes.length,
                arrRadius = [], // nodes size 数组
                maxRadius,
                arrDistance = [],
                maxDistance;

            $.each(graph.nodes, function (key, value) {
                arrRadius.push(value.size);
            });
            $.each(graph.links, function (key, value) {
                arrDistance.push(value.length); // 连接的个数
            });

            maxRadius = Math.max.apply(null, arrRadius);
            maxDistance = Math.max.apply(null, arrDistance);

            var k = Math.sqrt(graph.nodes.length / (width * height));

            var force = d3.layout.force()
                .nodes(graph.nodes)
                .links(graph.links)
                .size([width, height])
                .distance(function (d, i) {
                    dis = 200 + (400 - 200) * (d.length / maxDistance);
                    return dis;
                })
                .linkStrength(2)
                .charge((-10 / k) * 1.5)
                .gravity(100 * k)
                .on("tick", tick)
                .start();

            var nodes = force.nodes(),
                links = force.links();

            var drag = force.drag()
                .on("dragstart", dragstart);


            var svg = d3.select("#graphs").append("svg")
                .attr("width", width)
                .attr("height", height)
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            var marker = svg.append("defs").selectAll("marker")
                .data(force.links())
                .enter()
                .append("marker")
                .attr("id", function (d) {
                    return "marker-" + d.source.module_id + "-" + d.target.module_id;
                })
                .attr("viewBox", "0 -5 10 10")
                .attr("refX", 15)
                .attr("markerWidth", 4)
                .attr("markerHeight", 4)
                .attr("orient", "auto");

            marker.append("svg:path")
                .attr("d", "M0,-5L10,0L0,5");

            var path = svg.append("g").selectAll("path")
                .data(force.links())
                .enter().append("path")
                .attr("cursor", "pointer")
                .attr("class", function (d) {
                    return "link " + d.value;
                })
                .attr("marker-end", function (d) {
                    return "url(#marker-" + d.source.module_id + "-" + d.target.module_id + ")";
                });

            var node = svg.selectAll(".node")
                .data(force.nodes())
                .enter().append("g")
                .attr("class", "node")
                .attr("cursor", "pointer")
                .call(force.drag);

            node.append("circle")
                .attr("r", function (d) {
                    d.radius = 12 + (30 - 12) * (d.size / maxRadius); // 12半径最小，30半径最大
                    return d.radius;
                })
                .style("fill", function (d) {
                    if (parseInt(d.color, 10) == 1) {
                        return "#87cdfa";
                    } else {
                        return "red";
                    }

                });

            node.append("text")
                .attr("dx", 0)
                .attr("dy", ".35em")
                .text(function (d) {
                    return d.name;
                });

            node.append("title")
                .text(function (d) {
                    return d.name;
                });

            function tick(e) {
                path.attr("d", linkArc);
                node.attr("transform", transform);

                graph.links.forEach(function (d, i) {
                    d.source.y -= k;
                    d.target.y += k;
                });
            }

            function dragstart(d) {
                d3.select(this).classed("fixed", d.fixed = true);
            }

            function gravity(alpha) {
                return function (d) {
                    d.y += (d.cy - d.y) * alpha;
                    d.x += (d.cx - d.x) * alpha;
                };
            }


            function linkArc(d) {
                var diffX = d.target.x - d.source.x,
                    diffY = d.target.y - d.source.y,
                    pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY)), // 求对角线的值
                    offsetX = (diffX * d.target.radius) / pathLength, // 根据两个三角形求边缘点的坐标x 值
                    offsetY = (diffY * d.target.radius) / pathLength;

                // 弧线
                return "M" + d.source.x + "," + d.source.y + "A" + pathLength + "," + pathLength + " 0 0,1 " + (d.target
                    .x - offsetX) + "," + (d.target.y - offsetY);

                // 直线
                //return "M" + d.source.x + "," + d.source.y + "L" + (d.target.x - offsetX) + "," + (d.target.y - offsetY);

            }

            function transform(d) {
                return "translate(" + d.x + "," + d.y + ")";
            }
        }
        renderGraphs();
    })(window);
</script>

</html>